package stat

import (
	"context"
	"fmt"
	log "github.com/sirupsen/logrus"
	"go.mongodb.org/mongo-driver/bson"
	"go.mongodb.org/mongo-driver/bson/primitive"
	"go.mongodb.org/mongo-driver/mongo"
	"mongofix/conf"
	"mongofix/fixpostattr"
	"mongofix/model"
	"mongofix/quit_all_group"
	"mongofix/utils"
	"os"
	"strings"
	"time"
)

func StatGroupByUser(ctx context.Context, groupIdStr string, isSendMail bool) {

	groupIds := strings.Split(groupIdStr, ",")

	subjectName := fmt.Sprintf("[%v]群按人数据统计", time.Now().Format("2006-01-02"))
	var files = make([]*os.File, 0, len(groupIds))
	var fileNames = make([]string, 0, len(groupIds))

	for _, groupId := range groupIds {

		gcol := utils.GetColForGroupByGroupId(groupId)
		groupDao := conf.GroupDao.Database(conf.DB_GROUP).Collection(gcol)
		var groupMedol = &quit_all_group.Group{}
		if e := utils.MgoGet(ctx, groupDao, bson.M{"_id": groupId}, groupMedol); e != nil {
			log.Errorf("查询群信息失败,err%v", e)
			return
		}

		fileName := fmt.Sprintf("群[%v]按人统计数据.csv", groupMedol.Name)
		fileNames = append(fileNames, fileName)

		file, err2 := os.Create(fileName)
		if err2 != nil {
			log.Errorf("打开输出文件失败,err%v", err2)
			return
		}

		if len(groupId) <= 0 {
			log.Infof("groupID为空：%v", groupId)
			return
		}
		defer file.Close()
		files = append(files, file)

		log.Infof("打开文件" + fileName)

		//写文件头
		_, _ = file.Write([]byte(fmt.Sprintf("用户ID,昵称,最后登录时间,帖子数量,评论数量,点赞数量,\n")))

		col := utils.GetColForGroupMemberByGroupId(groupId)
		groupMemberDao := conf.GroupDao.Database(conf.DB_GROUP_MEBMER).Collection(col)

		postCol := utils.GetColForPostByGroupId(groupId)
		postDao := conf.PostDao.Database(conf.DB_POST).Collection(postCol)

		result, err := groupMemberDao.Find(ctx, bson.M{"gid": groupId})
		if err != nil {
			log.Infof("查询群成员失败：%v，%v", groupId, err)
			return
		}

		members := make([]*quit_all_group.GroupMember, 0, 0)

		err = result.All(ctx, &members)

		if err != nil {
			log.Infof("序列化群成员失败：%v,%v", groupId, err)
			return
		}
		log.Infof("查询群成员，个数：%v,groupId:%v", len(members), groupId)

		allPostResult, allPostErr := postDao.Find(ctx, bson.M{"gid": groupId})
		if allPostErr != nil {
			log.Errorf("查询所有的的post失败，gid%v,err%v", groupId, allPostErr)
			return
		}

		allPosts := make([]*fixpostattr.Post, 0, 0)
		allPostErr = allPostResult.All(ctx, &allPosts)
		if allPostErr != nil {
			log.Errorf("序列化所有的post失败，gid%v,err%v", groupId, err)
			return
		}

		log.Infof("一共有post:%v条", len(allPosts))

		postsMap := make(map[int]interface{})
		for _, p := range allPosts {
			postId, _ := utils.GetIdAndGroupIdForPostByPostId(p.PId)
			postsMap[postId] = &p
		}

		for _, m := range members {
			log.Infof("处理群成员:%v", m.UId)

			userCol := utils.GetColForUserByUserId(m.UId)
			userDao := conf.UserDaos[utils.GetDbForUserByUserId(m.UId)].Database(conf.DB_USER).Collection(userCol)

			user := userDao.FindOne(ctx, bson.M{"_id": m.UId})
			if user.Err() != nil {
				log.Errorf("查询用户信息失败，uid%v，gid%v,err%v", m.UId, m.GId, err)
				return
			}
			userModel := &model.User{}
			err = user.Decode(userModel)
			if err != nil {
				log.Errorf("序列化用户信息失败，uid%v，gid%v,err%v", m.UId, m.GId, err)
				return
			}

			lastLoginTime := "未登录过"
			if userModel.CreateTime > 1 {
				lastLoginTime = time.Unix(userModel.LastLoginTime/1000, userModel.LastLoginTime%1000).Format("2006-01-02 15:04:05")
			}
			log.Infof("查询到的用户信息：name:%v,lastLoginTime:%v", userModel.Name, lastLoginTime)

			_, err2 := file.Write([]byte(fmt.Sprintf("%v,%v,%v,", userModel.UId, userModel.Name, lastLoginTime)))
			if err2 != nil {
				log.Errorf("用户信息写文件失败：%v", err2)
				return
			}

			result, err := postDao.Find(ctx, bson.M{"uid": m.UId, "gid": m.GId})
			if err != nil {
				log.Errorf("查询用户的post失败，uid%v，gid%v,err%v", m.UId, m.GId, err)
				return
			}

			posts := make([]*fixpostattr.Post, 0, 0)
			err = result.All(ctx, &posts)
			if err != nil {
				log.Errorf("序列化post失败，uid%v，gid%v,err%v", m.UId, m.GId, err)
				return
			}
			_, err2 = file.Write([]byte(fmt.Sprintf("%v,", len(posts))))
			if err2 != nil {
				log.Errorf("Post信息写文件失败：%v", err2)
				return
			}

			log.Infof("查询到的用户Post信息,post条数：%v", len(posts))

			userOpDao := conf.CommentDao.Database(conf.DB_COMMENT_OP).Collection(utils.GetColForCommentOPByUserId(m.UId))

			commentOps := make([]*model.CommentOp, 0, 0)

			err = utils.MgoList(ctx, userOpDao, bson.M{"uid": m.UId}, &commentOps)
			if err != nil {
				log.Errorf("查询用户的comment失败，uid%v，gid%v,err%v", m.UId, m.GId, err)
				return
			}

			commentCount := 0
			for _, c := range commentOps {
				_, postId1 := utils.GetIdAndPostIdForCommentByCommentId(c.CId)
				if postsMap[postId1] != nil {
					commentCount++
				}
			}
			log.Infof("查询到的用户comment信息,comment条数：%v,", commentCount)
			_, err2 = file.Write([]byte(fmt.Sprintf("%v,", commentCount)))
			if err2 != nil {
				log.Errorf("comment写文件失败：%v", err2)
				return
			}

			log.Infof("uid:%v", m.UId)
			userPostOpDao := conf.PostDao.Database(conf.DB_USER_POST_OP).Collection(utils.GetColForUserPostOPByUserId(m.UId))

			log.Infof("db:%v,col:%v", conf.DB_USER_POST_OP, userPostOpDao.Name())

			userPostOpList := make([]*model.UserPostOp, 0, 0)

			err2 = utils.MgoList(ctx, userPostOpDao, bson.M{"uid": m.UId, "bid": m.GId}, &userPostOpList)
			if err2 != nil {
				log.Errorf("查询用户的userPostOP失败，uid%v，gid%v,err%v", m.UId, m.GId, err)
				return
			}

			log.Infof("查询到的用户userPostOP信息,userPostOP条数：%v", len(userPostOpList))

			_, err2 = file.Write([]byte(fmt.Sprintf("%v,", len(userPostOpList))))
			if err2 != nil {
				log.Errorf("userPostOP写文件失败：%v", err2)
				return
			}

			_, err2 = file.Write([]byte("\n"))

		}
	}
	sendMail(isSendMail, subjectName, files, fileNames)
}

func StatGroupByDay(ctx context.Context, groupIdStr string, isSendMail bool) {

	groupIds := strings.Split(groupIdStr, ",")

	var files = make([]*os.File, 0, len(groupIds))
	var fileNames = make([]string, 0, len(groupIds))
	subjectName := fmt.Sprintf("[%v]群按天数据统计", time.Now().Format("2006-01-02"))

	for _, groupId := range groupIds {

		gcol := utils.GetColForGroupByGroupId(groupId)
		groupDao := conf.GroupDao.Database(conf.DB_GROUP).Collection(gcol)

		var groupMedol = &quit_all_group.Group{}
		if e := utils.MgoGet(ctx, groupDao, bson.M{"_id": groupId}, groupMedol); e != nil {
			log.Errorf("查询群信息失败,err%v", e)
			return
		}

		fileName := fmt.Sprintf("群[%v]按天统计数据.csv", groupMedol.Name)
		fileNames = append(fileNames, fileName)

		file, err2 := os.Create(fileName)
		if err2 != nil {
			log.Errorf("打开输出文件失败,err%v", err2)
			return
		}

		if len(groupId) <= 0 {
			log.Infof("groupID为空：%v", groupId)
			return
		}
		defer file.Close()
		files = append(files, file)

		log.Infof("打开文件" + fileName)

		//写文件头
		_, _ = file.Write([]byte(fmt.Sprintf("日期,注册,帖子数量,评论数量,点赞数量,\n")))

		col := utils.GetColForGroupMemberByGroupId(groupId)
		groupMemberDao := conf.GroupDao.Database(conf.DB_GROUP_MEBMER).Collection(col)

		postCol := utils.GetColForPostByGroupId(groupId)
		postDao := conf.PostDao.Database(conf.DB_POST).Collection(postCol)

		commentDaoMap := make(map[int]*mongo.Collection)
		for i := 0; i < conf.Tia_comment_col_num; i++ {
			col := conf.CommentDao.Database(conf.DB_COMMENT).Collection(utils.GetColCommentByIndex(i))
			commentDaoMap[i] = col
		}

		userPostOPDaoMap := make(map[int]*mongo.Collection)
		for i := 0; i < conf.Tia_user_post_op_col_num; i++ {
			col := conf.PostDao.Database(conf.DB_USER_POST_OP).Collection(utils.GetColUerPostOpByIndex(i))
			userPostOPDaoMap[i] = col
		}

		beginTime := groupMedol.CreateTime

		endTime := time.Now().Unix() * 1000
		for beginTime < endTime {
			log.Infof("统计的日期日期：%v", time.Unix(beginTime/1000, 0).Format("2006-01-02"))
			begin, end := unixTimeTruncateHour(beginTime / 1000)

			//db.album_task.find({"uid":"325#u-53583#m_tias","$and":[{"ct":{"$gt":1}},{"ct":{"$lt":1610415794206}}]})
			gtAndLt := bson.A{bson.M{"ct": bson.M{"$gte": begin}}, bson.M{"ct": bson.M{"$lte": end}}}

			result, err := groupMemberDao.Find(ctx, bson.M{"gid": groupId, "$and": gtAndLt})

			//args, err := json.Marshal(bson.M{"gid": groupId, "$and": gtAndLt})
			//log.Infof("groupMember查询参数:%v", string(args))
			if err != nil {
				log.Infof("查询群成员失败：%v，%v", groupId, err)
				return
			}

			members := make([]*quit_all_group.GroupMember, 0, 0)

			err = result.All(ctx, &members)

			if err != nil {
				log.Infof("序列化群成员失败：%v,%v", groupId, err)
				return
			}
			log.Infof("查询群成员，个数：%v,groupId:%v", len(members), groupId)

			allPostResult, allPostErr := postDao.Find(ctx, bson.M{"gid": groupId, "$and": gtAndLt})
			if allPostErr != nil {
				log.Errorf("查询所有的的post失败，gid%v,err%v", groupId, allPostErr)
				return
			}

			allPosts := make([]*fixpostattr.Post, 0, 0)
			allPostErr = allPostResult.All(ctx, &allPosts)
			if allPostErr != nil {
				log.Errorf("序列化所有的post失败，gid%v,err%v", groupId, err)
				return
			}

			log.Infof("一共有post:%v条", len(allPosts))

			commentCount := 0
			userPostOpCount := 0
			rege := bson.M{"$regex": primitive.Regex{Pattern: ".*" + groupId, Options: "i"}}
			for i := 0; i < conf.Tia_comment_col_num; i++ {

				tmpCommentQueryResult, tmpCommentQueryErr := commentDaoMap[i].Find(ctx, bson.M{"pid": rege, "$and": gtAndLt})
				//args, err := json.Marshal(bson.M{"pid": "\\-" + groupId + "\\", "$and": gtAndLt})
				//log.Infof("tmpCommentQuery,COL:%v,查询参数:%v", commentDaoMap[i].Name(), string(args))
				if tmpCommentQueryErr != nil {
					log.Errorf("序列化所有的userPostOpCount失败，gid%v,err%v", groupId, err)
					return
				}
				tmpCommentList := make([]*model.Comment, 0, 0)
				tmpCommentQueryErr = tmpCommentQueryResult.All(ctx, &tmpCommentList)
				if tmpCommentQueryErr != nil {
					log.Errorf("序列化所有的Comment失败，gid%v,err%v", groupId, err)
					return
				}
				commentCount = commentCount + len(tmpCommentList)

				tmpUserPostOpQueryResult, tmpUserPostOpQueryErr := userPostOPDaoMap[i].Find(ctx, bson.M{"bid": groupId, "$and": gtAndLt})
				//args, err = json.Marshal(bson.M{"bid": groupId, "$and": gtAndLt})
				//log.Infof("tmpUserPostOpQuery，COL:%v,查询参数:%v", userPostOPDaoMap[i].Name(), string(args))
				if tmpUserPostOpQueryErr != nil {
					log.Errorf("序列化所有的userPostOpCount失败，gid%v,err%v", groupId, err)
					return
				}
				tmpUserPostOpList := make([]*model.UserPostOp, 0, 0)
				tmpUserPostOpQueryErr = tmpUserPostOpQueryResult.All(ctx, &tmpUserPostOpList)
				if tmpUserPostOpQueryErr != nil {
					log.Errorf("序列化所有的userPostOpCount失败，gid%v,err%v", groupId, err)
					return
				}
				userPostOpCount = userPostOpCount + len(tmpUserPostOpList)

			}

			_, _ = file.Write([]byte(fmt.Sprintf("%s,%d,%d,%d,%d,\n",
				time.Unix(beginTime/1000, 0).Format("2006-01-02"), len(members), len(allPosts), commentCount, userPostOpCount)))

			beginTime = time.Unix(beginTime/1000, 0).Add(24*time.Hour).Unix() * 1000
		}
	}

	sendMail(isSendMail, subjectName, files, fileNames)

}

func unixTimeTruncateHour(unixTime int64) (begin int64, end int64) {
	beginTime, err := time.ParseInLocation("2006-01-02 15:04:05", fmt.Sprintf("%v 00:00:00", time.Unix(unixTime, 0).Format("2006-01-02")), time.Local)
	if err != nil {
		log.Errorf("开始时间转换错误：%v", unixTime)
		return 0, 0
	}

	endTime, err := time.ParseInLocation("2006-01-02 15:04:05", fmt.Sprintf("%v 23:59:59", time.Unix(unixTime, 0).Format("2006-01-02")), time.Local)

	if err != nil {
		log.Errorf("结束时间转换错误：%v", unixTime)
		return 0, 0
	}
	return beginTime.Unix() * 1000, endTime.Unix() * 1000
}

func sendMail(isSendMail bool, subjectName string, files []*os.File, fileNames []string) {
	if isSendMail {
		for _, file := range files {
			file.Close()
		}

		mailTo := []string{"lizhikui@xiaoniangao.com"}
		if conf.Env == conf.PROD {
			mailTo = append(mailTo, "chenshanshan@xiaoniangao.com", "tengzhijia@xiaoniangao.com")
		}

		if e := utils.SendMail(subjectName, mailTo, fileNames...); e != nil {
			log.Errorf("发送邮件失败，err:%v", e)
		}
		log.Infof("发送邮件成功，TO:%v", mailTo)

		for _, fileName := range fileNames {
			os.Remove(fileName)
		}
	}
}
